home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / passwd+ / load.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  15.2 KB  |  623 lines

  1. /*
  2.  * initialization routines
  3.  * this initializes various things used to verify the
  4.  * validity of the password
  5.  */
  6. #include "passwd.h"
  7.  
  8. /*
  9.  * this table contains all the information one could ever want to know
  10.  * about the internal variables
  11.  */
  12. struct intvar  iv[] = {
  13.     { 'A', TY_STR, CH_NULL, CH_NULL, 1, "user variable A [%s]: ",     },
  14.     { 'B', TY_STR, CH_NULL, CH_NULL, 1, "user variable B [%s]: ",     },
  15.     { 'C', TY_STR, CH_NULL, CH_NULL, 1, "user variable C [%s]: ",     },
  16.     { 'D', TY_STR, CH_NULL, CH_NULL, 1, "user variable D [%s]: ",     },
  17.     { 'E', TY_STR, CH_NULL, CH_NULL, 1, "user variable E [%s]: ",     },
  18.     { 'F', TY_STR, CH_NULL, CH_NULL, 1, "user variable F [%s]: ",     },
  19.     { 'G', TY_STR, CH_NULL, CH_NULL, 1, "user variable G [%s]: ",     },
  20.     { 'H', TY_STR, CH_NULL, CH_NULL, 1, "user variable H [%s]: ",     },
  21.     { 'I', TY_STR, CH_NULL, CH_NULL, 1, "user variable I [%s]: ",     },
  22.     { 'J', TY_STR, CH_NULL, CH_NULL, 1, "user variable J [%s]: ",     },
  23.     { 'K', TY_STR, CH_NULL, CH_NULL, 1, "user variable K [%s]: ",     },
  24.     { 'L', TY_STR, CH_NULL, CH_NULL, 1, "user variable L [%s]: ",     },
  25.     { 'M', TY_STR, CH_NULL, CH_NULL, 1, "user variable M [%s]: ",     },
  26.     { 'N', TY_STR, CH_NULL, CH_NULL, 1, "user variable N [%s]: ",     },
  27.     { 'O', TY_STR, CH_NULL, CH_NULL, 1, "user variable O [%s]: ",     },
  28.     { 'P', TY_STR, CH_NULL, CH_NULL, 1, "user variable P [%s]: ",     },
  29.     { 'Q', TY_STR, CH_NULL, CH_NULL, 1, "user variable Q [%s]: ",     },
  30.     { 'R', TY_STR, CH_NULL, CH_NULL, 1, "user variable R [%s]: ",     },
  31.     { 'S', TY_STR, CH_NULL, CH_NULL, 1, "user variable S [%s]: ",     },
  32.     { 'T', TY_STR, CH_NULL, CH_NULL, 1, "user variable T [%s]: ",     },
  33.     { 'U', TY_STR, CH_NULL, CH_NULL, 1, "user variable U [%s]: ",     },
  34.     { 'V', TY_STR, CH_NULL, CH_NULL, 1, "user variable V [%s]: ",     },
  35.     { 'W', TY_STR, CH_NULL, CH_NULL, 1, "user variable W [%s]: ",     },
  36.     { 'X', TY_STR, CH_NULL, CH_NULL, 1, "user variable X [%s]: ",     },
  37.     { 'Y', TY_STR, CH_NULL, CH_NULL, 1, "user variable Y [%s]: ",     },
  38.     { 'Z', TY_STR, CH_NULL, CH_NULL, 1, "user variable Z [%s]: ",     },
  39.     { 'a', TY_NUM, CH_NULL, CH_NULL, 0, CH_NULL, /* alphanumerics */ },
  40.     { 'b', TY_NUM, CH_NULL, CH_NULL, 0, CH_NULL, /* alphabetics */     },
  41.     { 'c', TY_NUM, CH_NULL, CH_NULL, 0, CH_NULL, /* capitals */     },
  42.     { 'd', TY_STR, CH_NULL, CH_NULL, 0, CH_NULL, /* domain name */     },
  43.     { 'f', TY_STR, CH_NULL, CH_NULL, 1, "First Name [%s]: ",     },
  44.     { 'g', TY_STR, CH_NULL, CH_NULL, 0, CH_NULL, /* group name */     },
  45.     { 'h', TY_STR, CH_NULL, CH_NULL, 0, CH_NULL, /* host name */     },
  46.     { 'i', TY_STR, CH_NULL, CH_NULL, 1, "Initials [%s]: ",         },
  47.     { 'l', TY_NUM, CH_NULL, CH_NULL, 0, CH_NULL, /* small letters */ },
  48.     { 'm', TY_STR, CH_NULL, CH_NULL, 1, "Middle Name [%s]: ",     },
  49.     { 'n', TY_STR, CH_NULL, CH_NULL, 1, "Full Name [%s]: ",         },
  50.     { 'o', TY_STR, CH_NULL, CH_NULL, 1, "Office [%s]: ",         },
  51.     { 'p', TY_STR, CH_NULL, CH_NULL, 0, CH_NULL, /* new password */  },
  52.     { 'q', TY_STR, CH_NULL, CH_NULL, 0, CH_NULL, /* old password */     },
  53.     { 's', TY_STR, CH_NULL, CH_NULL, 1, "Last Name [%s]: ",         },
  54.     { 't', TY_STR, CH_NULL, CH_NULL, 1, "Phone Number [%s]: ",     },
  55.     { 'u', TY_STR, CH_NULL, CH_NULL, 0, CH_NULL, /* user name */     },
  56.     { 'v', TY_NUM, CH_NULL, CH_NULL, 0, CH_NULL, /* mixed case */     },
  57.     { 'w', TY_NUM, CH_NULL, CH_NULL, 0, CH_NULL, /* digits */     },
  58.     { '\0',TY_NUM, CH_NULL, CH_NULL, 0, CH_NULL, /* END-OF-LIST */     },
  59. };
  60.  
  61. /*
  62.  * this initializes the variables associated with the password
  63.  */
  64. initpw()
  65. {
  66.     char buf[BUFSIZ];        /* buffer for string constants */
  67.     register char *p;        /* pointer in a for loop */
  68.     struct group *g;        /* points to user's group info */
  69.     int len;            /* length of password */
  70.     int iupper;            /* number of uppercase characters */
  71.     int ilower;            /* number of lowercase characters */
  72.     int ialpha;            /* number of alphabetic characters */
  73.     int inum;            /* number of numeric characters */
  74.     int ialnum;            /* number of alphanumeric characters */
  75.  
  76.     /*
  77.      * assign the password, name, host, domain, etc.
  78.      */
  79.     if (pwsig > 0){
  80.         (void) strncpy(buf, password, pwsig);
  81.         buf[pwsig] = '\0';
  82.         IVSASSIGN('p', buf);
  83.     }
  84.     else
  85.         IVSASSIGN('p', password);
  86.     if (pwsig > 0){
  87.         (void) strncpy(buf, oldpassword, pwsig);
  88.         buf[pwsig] = '\0';
  89.         IVSASSIGN('q', buf);
  90.     }
  91.     else
  92.         IVSASSIGN('q', oldpassword);
  93.     IVSASSIGN('u', pwinfo->pw_name);
  94.     if ((g = getgrgid(pwinfo->pw_gid)) == GR_NULL)
  95.         IVSASSIGN('g', CH_NULL)        /* no semicolon here! */
  96.     else
  97.         IVSASSIGN('g', g->gr_name);
  98.     if (findhost(buf, BUFSIZ) < 0)
  99.         IVSASSIGN('h', CH_NULL)        /* no semicolon here! */
  100.     else
  101.         IVSASSIGN('h', buf);
  102.     if (finddomain(buf, BUFSIZ) < 0)
  103.         IVSASSIGN('d', CH_NULL)        /* no semicolon here! */
  104.     else
  105.         IVSASSIGN('d', buf);
  106.  
  107.     /*
  108.      * do some quick counts of characters
  109.      * only the first pwsig characters count
  110.      */
  111.     len = iupper = ilower = ialpha = inum = ialnum = 0;
  112.     for(p = findiv('p')->string; *p; p++){
  113.         len++;            /* one more to the length */
  114.         if (isupper(*p))    /* upper case */
  115.             iupper++;
  116.         else if (islower(*p))    /* lower case */
  117.             ilower++;
  118.         if (isalpha(*p)){    /* alphabetic */
  119.             ialpha++;
  120.             ialnum++;
  121.         }
  122.         else if (isdigit(*p)){    /* numeric */
  123.             inum++;
  124.             ialnum++;
  125.         }
  126.     }
  127.     IVNASSIGN('a', ialnum, len - ialnum); 
  128.     IVNASSIGN('b', ialpha, len - ialpha); 
  129.     IVNASSIGN('c', iupper, len - iupper); 
  130.     IVNASSIGN('l', ilower, len - ilower); 
  131.     IVNASSIGN('v', !(iupper && ilower), (iupper && ilower));
  132.     IVNASSIGN('w', inum, len - inum); 
  133. }
  134.  
  135. /*
  136.  * load the number of significant chars in the password
  137.  */
  138. loadsig(number)
  139. char *number;
  140. {
  141.     register int sgn;        /* 1 if number is negative */
  142.     char buf[BUFSIZ];        /* buffer for new password */
  143.  
  144.     /*
  145.      * skip leading blanks
  146.      */
  147.     while(isspace(*number))
  148.         number++;
  149.     /*
  150.      * grab the sign if any
  151.      */
  152.     sgn = 0;
  153.     if (*number == '+' || *number == '-')
  154.         sgn = (*number++ == '-');
  155.     /*
  156.      * if there's no number, ignore the line
  157.      */
  158.     if (!isdigit(*number))
  159.         return;
  160.     /*
  161.      * read the number as the number of significant characters
  162.      * and set the sign properly
  163.      */
  164.     pwsig = 0;
  165.     while(isdigit(*number))
  166.         pwsig = pwsig * 10 + *number++ - '0';
  167.     if (sgn)
  168.         pwsig = -pwsig;
  169.     else if (pwsig >= BUFSIZ)
  170.         pwsig = BUFSIZ-1;
  171.     /*
  172.      * now reset the password to be interpolated
  173.      */
  174.     if (pwsig > 0){
  175.         (void) strncpy(buf, password, pwsig);
  176.         buf[pwsig] = '\0';
  177.         IVSASSIGN('p', buf);
  178.     }
  179.     else
  180.         IVSASSIGN('p', password);
  181.     LOG2(LG_DEBUG, "passwd: \"%s\",\"%s\"",
  182.                 findiv('p')->string, findiv('p')->length);
  183. }
  184.  
  185. /*
  186.  * load the escapes defined by the GECOS field
  187.  */
  188. loadgecos(format, prfmt, list)
  189. char *format;            /* what to analyze */
  190. char *prfmt;            /* printf format string */
  191. char *list;            /* how to parse it */
  192. {
  193.     register char *f, *fb;    /* used to collect the format string */
  194.     char fbuf[BUFSIZ];    /* format string stuffed here */
  195.     register int i;        /* counter in a for loop */
  196.     register int n;        /* number of strings read in */
  197.     char pbuf[2*BUFSIZ];    /* buffer for gecos field (no &s) */
  198.                 /* space for strings */
  199.     char addr1[GECOSSIZE], addr2[GECOSSIZE], addr3[GECOSSIZE];
  200.     char addr4[GECOSSIZE], addr5[GECOSSIZE], addr6[GECOSSIZE];
  201.     char addr7[GECOSSIZE], addr8[GECOSSIZE], addr9[GECOSSIZE];
  202.     char *addrs[9];        /* walks the above arrays */
  203.     int ff = 0;        /* 1 if first name read */
  204.     int fm = 0;        /* 1 if middle name read */
  205.     int fl = 0;        /* 1 if last name read */
  206.     int fn = 0;        /* 1 if full name read */
  207.     int fi = 0;        /* 1 if initials read */
  208.     struct intvar *ip;    /* points to internal variable */
  209.  
  210.     /*
  211.      * initialize the reading areas
  212.      */
  213.     addrs[0] = addr1; addrs[1] = addr2; addrs[2] = addr3;
  214.     addrs[3] = addr4; addrs[4] = addr5; addrs[5] = addr6;
  215.     addrs[6] = addr7; addrs[7] = addr8; addrs[8] = addr9;
  216.     /*
  217.      * expand gecos field, replacing & by login name
  218.      */
  219.     fb = pbuf;
  220.     for(f = pwinfo->pw_gecos; *f; f++)
  221.         if (*f == '&'){
  222.             if (pwinfo->pw_name != CH_NULL){
  223.                 register char *ob = pwinfo->pw_name;
  224.                 while(*ob)
  225.                     *fb++ = *ob++;
  226.             }
  227.         }
  228.         else
  229.             *fb++ = *f;
  230.     *fb = '\0';
  231.  
  232.     /*
  233.      * now read in the format string
  234.      */
  235.     for(f = format; *f && *f != '"'; f++);
  236.     /*
  237.      * none present -- skip line
  238.      */
  239.     if (!*f)
  240.         return(-1);
  241.     /*
  242.      * skip initial quote, stuff string
  243.      */
  244.     if (prfmt == CH_NULL)
  245.         fb = fbuf;
  246.     else
  247.         fb = prfmt;
  248.     for(f++; *f && *f != '"'; *fb++ = *f++);
  249.     *fb = '\0';
  250.     /*
  251.      * no closing quote -- ignore line
  252.      */
  253.     if (!*f){
  254.         LOG1(LG_SYNTAX,
  255.             "missing \" in GECOS specification on line %d", linect);
  256.         return(-1);
  257.     }
  258.     /*
  259.      * skip closing quote
  260.      */
  261.     f++;
  262.  
  263.     /*
  264.      * read in the strings
  265.      */
  266.     n = sscanf(pbuf, (prfmt == CH_NULL) ? fbuf : prfmt,
  267.                     addr1, addr2, addr3, addr4, addr5,
  268.                         addr6, addr7, addr8, addr9);
  269.     /*
  270.      * quickly check the format of the symbols
  271.      */
  272.     fb = f;
  273.     i = 0;
  274.     while(*fb && (findiv(*fb) != IV_NULL || isspace(*fb))){
  275.         if (!isspace(*fb))
  276.             i++;
  277.         fb++;
  278.     }
  279.     if (*fb && findiv(*fb) == IV_NULL){
  280.         LOG2(LG_SYNTAX,
  281.             "bad GECOS specification at line %d (\"%s\")",
  282.                                 linect, fb);
  283.         return(-1);
  284.     }
  285.     else if (i != n){
  286.         LOG1(LG_SYNTAX,
  287.             "wrong number of escapes in GECOS specification on line %d",
  288.                 linect);
  289.         return(-1);
  290.     }
  291.         
  292.     /*
  293.      * process them
  294.      */
  295.     for(i = 0; i < n; i++){
  296.         /*
  297.          * skip white space
  298.          */
  299.         while(isspace(*f))
  300.             f++;
  301.         /*
  302.          * next char says what it is
  303.          */
  304.         if (list != CH_NULL)
  305.             *list++ = *f;
  306.         if (*f == '\0' || *f == '\n')
  307.             break;
  308.         /*
  309.          * make the assignment or report an error
  310.          */
  311.         ip = findiv(*f++);
  312.         if (!ip->userset){
  313.             LOG2(LG_SYNTAX,
  314.                 "bad GECOS specification at line %d (\"%s\")",
  315.                             linect, &f[-1]);
  316.             break;
  317.         }
  318.         IVSPASSIGN(ip, addrs[i]);
  319.         switch(ip->name){
  320.         case 'f':    ff++; break;    /* first name */
  321.         case 'm':    fm++; break;    /* middle name */
  322.         case 's':    fl++; break;    /* last name */
  323.         case 'i':    fi++; break;    /* initials */
  324.         case 'n':    fn++; break;    /* full name */
  325.         }
  326.     }
  327.     if (list != CH_NULL)
  328.         *list = '\0';
  329.  
  330.     /*
  331.      * if the full name is given derive the first, middle, and last
  332.      */
  333.     ip = findiv('n');
  334.     if (fn && (f = index(ip->string, ',')) == NULL){
  335.         /*
  336.          * name is of the form "first middle last"
  337.          * so get the last name first and stuff it in
  338.          * addr1
  339.          */
  340.         f = ip->string;
  341.         for(fb = addr1; isalpha(*f) || *f == '-'; *fb++ = *f++);
  342.         *fb = '\0';
  343.         /*
  344.          * now go for the second name
  345.          * skip leading white spaces
  346.          */
  347.         while(*f && !isalpha(*f))
  348.             f++;
  349.         if (*f){
  350.             /*
  351.              * if there is a second name, the first was
  352.              * the first name; assign it
  353.              */
  354.             if (!ff)
  355.                 IVSASSIGN('s', addr2);
  356.             /*
  357.              * grab the second name
  358.              */
  359.             for(fb = addr2; isalpha(*f) || *f == '-'; *fb++ = *f++);
  360.             *fb = '\0';
  361.             /*
  362.              * now go for the third name
  363.              * skip leading white spaces
  364.              */
  365.             while(*f && !isalpha(*f))
  366.                 f++;
  367.             if (*f){
  368.                 /*
  369.                  * grab the third name
  370.                  */
  371.                 for(fb = addr3; isalpha(*f) || *f == '-';
  372.                                 *fb++ = *f++);
  373.                 *fb = '\0';
  374.                 /*
  375.                  * assign the middle and last names (phew!)
  376.                  */
  377.                 if (!fm)
  378.                     IVSASSIGN('m', addr2);
  379.                 if (!fl)
  380.                     IVSASSIGN('s', addr3);
  381.             }
  382.             /*
  383.              * two names only; assign last name
  384.              */
  385.             else if (!fl)
  386.                 IVSASSIGN('s', addr2);
  387.         }
  388.         /*
  389.          * one name only; assign as last name
  390.          */
  391.         else if (!fl)
  392.             IVSASSIGN('s', addr1);
  393.     }
  394.     else if (fn){
  395.         /*
  396.          * name is of the form "last, first middle"
  397.          * so get the last name first and stuff it in
  398.          * addr1
  399.          */
  400.         f = ip->string;
  401.         for(fb = addr1; isalpha(*f) || *f == '-'; *fb++ = *f++);
  402.         *fb = '\0';
  403.         /*
  404.          * if last name not known, assign it
  405.          */
  406.         if (!fl)
  407.             IVSASSIGN('s', addr1);
  408.         /*
  409.          * now go for the first and middle names
  410.          * skip nonletters spaces
  411.          */
  412.         while(*f && !isalpha(*f))
  413.             f++;
  414.         if (*f){
  415.             /*
  416.              * get the next name and save it in addr1
  417.              */
  418.             for(fb = addr1; isalpha(*f) || *f == '-'; *fb++ = *f++);
  419.             *fb = '\0';
  420.             /*
  421.              * if first name not known, you got it
  422.              */
  423.             if (!ff)
  424.                 IVSASSIGN('f', addr1);
  425.             /*
  426.              * now go for the middle name
  427.              * skip nonletters spaces
  428.              */
  429.             while(*f && !isalpha(*f))
  430.                 f++;
  431.             if (*f){
  432.                 /*
  433.                  * get the next name and save it in addr1
  434.                  */
  435.                 for(fb = addr1; isalpha(*f) || *f == '-';
  436.                                 *fb++ = *f++);
  437.                 *fb = '\0';
  438.                 /*
  439.                  * if middle name not known, you got it
  440.                  */
  441.                 if (!fm)
  442.                     IVSASSIGN('m', addr1);
  443.             }
  444.         }
  445.         /*
  446.          * the name must now be rebuilt in the more usual form
  447.          * "first middle last"; the next part does this, so we
  448.          * force it to be taken by pretending we never saw the name
  449.          */
  450.         fn = 0;
  451.     }
  452.  
  453.     /*
  454.      * full name not yet known -- fill it in
  455.      */
  456.     if (!fn){
  457.         /*
  458.          * load into buffer one name at a time,
  459.          * including spaces between the relevant names
  460.          */
  461.         fbuf[0] = '\0';
  462.         ip = findiv('f');
  463.         if (ip->string != CH_NULL)
  464.             (void) strcat(fbuf, ip->string);
  465.         ip = findiv('m');
  466.         if (ip->string != CH_NULL){
  467.             if (fbuf[0] != '\0')
  468.                 (void) strcat(fbuf, " ");
  469.             (void) strcat(fbuf, ip->string);
  470.         }
  471.         ip = findiv('s');
  472.         if (ip->string != CH_NULL){
  473.             if (fbuf[0] != '\0')
  474.                 (void) strcat(fbuf, " ");
  475.             (void) strcat(fbuf, ip->string);
  476.         }
  477.         /*
  478.          * if there's anything, assign it as initials
  479.          */
  480.         if (strlen(fbuf) > 0)
  481.             IVSASSIGN('n', fbuf);
  482.     }
  483.     /*
  484.      * initials not yet known -- fill them in
  485.      */
  486.     if (!fi){
  487.         /*
  488.          * load into temp buffer one name at a time, in lower case
  489.          */
  490.         f = fbuf;
  491.         ip = findiv('f');
  492.         if (ip->string != CH_NULL && ip->string[0] != '\0')
  493.             *f++ = lowcase(ip->string[0]);
  494.         ip = findiv('m');
  495.         if (ip->string != CH_NULL && ip->string[0] != '\0')
  496.             *f++ = lowcase(ip->string[0]);
  497.         ip = findiv('s');
  498.         if (ip->string != CH_NULL && ip->string[0] != '\0')
  499.             *f++ = lowcase(ip->string[0]);
  500.         *f = '\0';
  501.         /*
  502.          * if there's anything, assign it as initials
  503.          */
  504.         if (strlen(fbuf) > 0)
  505.             IVSASSIGN('i', fbuf);
  506.     }
  507.  
  508.     /*
  509.      * if debugging print out some goodies
  510.      */
  511.     for(i = 0; iv[i].name != '\0'; i++){
  512.         if (iv[i].userset)
  513.             LOG3(LG_DEBUG, "variable %c: \"%s\",\"%s\"",
  514.                 iv[i].name, iv[i].string, iv[i].length);
  515.     }
  516.     return(0);
  517. }
  518.  
  519. /*
  520.  * set a variable
  521.  */
  522. setvar(buf)
  523. char *buf;                /* line buffer */
  524. {
  525.     char keychar;        /* what to set */
  526.     char closechar;        /* how to end value string */
  527.     char valbuf[BUFSIZ];    /* value */
  528.  
  529.     /*
  530.      * eat leading spaces; if nothing, done!
  531.      */
  532.     while(isspace(*buf))
  533.         buf++;
  534.     if (!*buf)
  535.         return;
  536.     /*
  537.      * it's the key character
  538.      */
  539.     keychar = *buf++;
  540.  
  541.     /*
  542.      * move to next nonblank
  543.      */
  544.     while(isspace(*buf))
  545.         buf++;
  546.  
  547.     /*
  548.      * now act on it
  549.      */
  550.     switch(*buf++){
  551.     case '"':            /* string */
  552.         closechar = '"';
  553.         break;
  554.     case '[':            /* file name */
  555.         closechar = ']';
  556.         break;
  557.     case '{':            /* program name */
  558.         closechar = '}';
  559.         break;
  560.     default:            /* something else (bad) */
  561.         LOG2(LG_SYNTAX,
  562.             "bad SETVAR specification at line %d (\"%s\")",
  563.                             linect, &buf[-1]);
  564.         return;
  565.     }
  566.  
  567.     /*
  568.      * copy the value into the buffer
  569.      * if not terminated properly, error
  570.      */
  571.     if (*(buf = getcstring(buf, valbuf, closechar)) != closechar){
  572.         LOG2(LG_SYNTAX,
  573.             "missing %c in SETVAR specification on line %d",
  574.                             closechar, linect);
  575.         return;
  576.     }
  577.  
  578.     /*
  579.      * if it's a program or a file, grab the first line
  580.      */
  581.     if (closechar == ']' && 
  582.         firstline(valbuf, valbuf, BUFSIZ, fopen, fclose) == 0)
  583.             return;
  584.     else if (closechar == '}' && 
  585.         firstline(valbuf, valbuf, BUFSIZ, popen, pclose) == 0)
  586.             return;
  587.  
  588.     /*
  589.      * now set the sucker
  590.      */
  591.     if (!findiv(keychar)->userset){
  592.         LOG2(LG_SYNTAX,
  593.             "bad SETVAR specification at line %d (\"%s\")",
  594.                             linect, &buf[-1]);
  595.     }
  596.     else{
  597.         IVSASSIGN(keychar, valbuf);
  598.     }
  599. }
  600.  
  601. /*
  602.  * load the logging level
  603.  */
  604. loadlevel(line)
  605. char *line;
  606. {
  607.     beginlog(line);
  608. }
  609.  
  610. /*
  611.  * returns a pointer to an internal variable
  612.  */
  613. struct intvar *findiv(c)
  614. char c;            /* internal variable name */
  615. {
  616.     register struct intvar *ip;    /* pointer to internal variable */
  617.  
  618.     for(ip = &iv[0]; ip->name != '\0'; ip++)
  619.         if (ip->name == c)
  620.             return(ip);
  621.     return(IV_NULL);
  622. }
  623.